import { createDOM } from './react-dom'
export let updateQueue = {
  isBatchingUpdate: false, // 当前是否采用批量更新
  updaters: new Set(),
  batchUpdate() {
    for (let updater of this.updaters) {
      updater.updateClassComponent()
    }
    this.isBatchingUpdate = false
  }
}
class Updater{
  constructor(classInstance) {
    this.classInstance = classInstance // 类组件实例
    this.pendingStates = [] // 等待生效的状态，可能是对象，可能是函数 
    this.callbacks = [] // 状态更新后的回调
  }
  addState(partialState, callback) {
    // 待生效状态加入到待生效队列中
    this.pendingStates.push(partialState)
    if (typeof callback === 'function') {
      // 如果传入了callback，则加入到回调队列中
      this.callbacks.push(callback)
    }
    if (updateQueue.isBatchingUpdate) {
      // 当前处于批量更新模式，故先在更新队列中缓存，此处setState执行结束
      updateQueue.updaters.add(this)
    } else {
      // 不是批量更新模式，直接更新组件
      this.updateClassComponent()
    }
  }
  // 更新类组件
  updateClassComponent() {
    let { classInstance, pendingStates, callbacks } = this
    if (pendingStates.length > 0) {
      // 如果有待生效的状态，则计算最新状态，然后更新
      // 计算最新状态
      classInstance.state = this.getState()
      // 类实例强制更新
      classInstance.forceUpdate()
      // 执行状态更新后的回调,然后清空
      callbacks.forEach(cb => cb())
      callbacks.length = 0
    }
  }
  getState() {
    let { classInstance, pendingStates } = this
    let { state } = classInstance
    // 将带更新的状态逐个组合到一个对象中
    pendingStates.forEach((nextState) => {
      // 如果待更新状态是一个函数，那么保存函数的执行结果
      if (typeof nextState === 'function') {
        nextState = nextState.call(classInstance, state)
      }
      state = { ...state, ...nextState }
    })
    // 在不回收原数组的情况下清空数组  若使用pendingStates = []则会回收原数组，创建一个新数组
    pendingStates.length = 0
    return state
  }
}
class Component{
  static isReactComponent = true
  constructor(props) {
    this.props = props
    this.state = {}
    this.updater = new Updater(this)
  }
  setState(partialState, callback) {
    // 将当前state和传入的部分state合并成新的this.state，然后更新类组件
    // let state = this.state
    // this.state = { ...state, ...partialState }
    // 此处的this表示子类，调用的是子类上定义的render方法
    // let newVdom = this.render()
    // updateClassComponent(this, newVdom)
    this.updater.addState(partialState, callback)
  }
  // 类实例强制更新
  forceUpdate() {
    // 调用类组件的render方法生成新的虚拟dom
    let newVdom = this.render()
    // 用新的虚拟dom更新类组件的真实dom
    updateClassComponent(this, newVdom)
  }
  render() {
    throw new Error('此方法为抽象方法，需要子类实现')
  }
}

/**
 * 用新的虚拟dom更新类组件真实dom
 * @param {*} classInstance 类组件实例
 * @param {*} newVdom 虚拟dom
 */
function updateClassComponent(classInstance, newVdom) {
  // 取出当前类组件实例上次渲染的真实dom
  let oldDom = classInstance.dom
  // 通过新的虚拟dom生成新的真实dom
  let newDom = createDOM(newVdom)
  // 新的真实dom替换老的真实dom
  oldDom.parentNode.replaceChild(newDom, oldDom)
  // 新的真实dom挂载到类组件实例上，用于下一次更新
  classInstance.dom = newDom
}
export default Component